package bus

import chisel3._
import chisel3.util._
import utils._

class CBus32To64 extends Module {
    val io = IO(new Bundle{
        val in  = Flipped(new CBus32Bundle(32, 32))
        val out = new CBus64Bundle(64, 32)
        val clk2en = Input(Bool())
    })
    val in = io.in
    val out = io.out

    val s1 = withReset((~reset.asBool).asAsyncReset)(Module(new Queue(in.req.bits.cloneType, 1, pipe = true, flow = false)))
    val req_fifo = withReset((~reset.asBool).asAsyncReset)(Module(new SynFifoWithClk2en(out.req.bits.cloneType, entries = 2)))    // TODO:
    val req_type = Wire(new Bundle{
        val addr2 = Bool()
        val mr = Bool()
    })
    req_type.addr2 := req_fifo.io.deq.bits.addr(2)
    req_type.mr := req_fifo.io.deq.bits.mr
    val req_type_fifo = withReset((~reset.asBool).asAsyncReset)(Module(new Queue(req_type.cloneType, entries = 3)))
    val resp_fifo = withReset((~reset.asBool).asAsyncReset)(Module(new Queue(out.resp.bits.cloneType, entries = 3)))
    val extend_cycle = RegInitA(reset, false.B)

    // mr
    val mr1 = (in.req.bits.addr(31,3) === s1.io.deq.bits.addr(31,3)) & in.req.bits.addr(2) & !s1.io.deq.bits.addr(2) 
    val mr2 = (s1.io.deq.bits.we === in.req.bits.we) & s1.io.deq.bits.be.andR & in.req.bits.be.andR
    val mr = mr1 & mr2

    // in -> s1
    s1.io.enq.valid := in.req.valid & (!(mr & s1.io.deq.valid))
    s1.io.enq.bits := in.req.bits
    s1.io.deq.ready := req_fifo.io.enq.ready

    // in -> req_fifo
    req_fifo.clk2en := io.clk2en
    req_fifo.io.enq.valid := s1.io.deq.valid
    req_fifo.io.enq.bits.addr := s1.io.deq.bits.addr
    req_fifo.io.enq.bits.we := s1.io.deq.bits.we
    req_fifo.io.enq.bits.be := s1.io.deq.bits.be
    req_fifo.io.enq.bits.hprot := s1.io.deq.bits.hprot
    req_fifo.io.enq.bits.wdata := Mux(s1.io.deq.bits.addr(2), Cat(s1.io.deq.bits.wdata, 0.U(32.W)), Cat(in.req.bits.wdata, s1.io.deq.bits.wdata))
    req_fifo.io.enq.bits.mr := in.req.valid & mr

    // out.req
    out.req <> req_fifo.io.deq

    // in.req
    in.req.ready := s1.io.enq.ready | req_fifo.io.enq.ready

    // req_type_fifo
    req_type_fifo.io.enq.valid := req_fifo.io.deq.fire
    req_type_fifo.io.enq.bits := req_type
    req_type_fifo.io.deq.ready := (!req_type_fifo.io.deq.bits.mr | extend_cycle) & resp_fifo.io.deq.valid

    // resp_fifo
    resp_fifo.io.enq.valid <> out.resp.valid
    resp_fifo.io.enq.bits <> out.resp.bits
    resp_fifo.io.deq.ready := (!req_type_fifo.io.deq.bits.mr | extend_cycle) & resp_fifo.io.deq.valid

    // in.resp
    extend_cycle := !extend_cycle & resp_fifo.io.deq.valid & req_type_fifo.io.deq.bits.mr

    in.resp.valid := resp_fifo.io.deq.valid
    in.resp.bits.err := resp_fifo.io.deq.bits.err // 要返回两个err信号吗
    in.resp.bits.rdata := Mux(extend_cycle === req_type_fifo.io.deq.bits.addr2, resp_fifo.io.deq.bits.rdata(31,0), resp_fifo.io.deq.bits.rdata(63,32))
}